release: cut-release.sh — reproducible release bundle from a clean tree (vms-d73) - #279
Merged
Merged
Conversation
…e from a clean tree, byte-reproducibly (vms-d73) Foundation of the Release Engineering pillar (epic vms-a84): replaces the hand-rolled per-cut process (build, copy artifacts, hand-write checksums) with tools/cut-release.sh, which git-archives HEAD to a clean /tmp tree (never builds into the repo), drives the existing containerized distro/Dockerfile.bootable build via `docker buildx build --output=local`, and writes dist/release-<version>/ with vmlinuz, initramfs-ovmx-slim.cpio.gz, ovmx-distrib.img, ovmx-os.kit, SHA256SUMS, and an OVMX-defined (Rule 8) release-manifest.json. Version is single-sourced from the archived src/libvms/include/ovmx_identity.h -- no literal in the script. Byte-reproducibility required normalizing every wall-clock the build stamps into a shipped artifact: SOURCE_DATE_EPOCH now threads through Dockerfile.bootable (new build-arg, default 0) into cpio/gzip packing (mtime-normalized + sorted file lists + gzip -n) and into tools/ovmx_kit_pack.c / tools/vmsfs_master.c, which previously stamped time(NULL) into the OS kit header and the mastered VMSFS image's file timestamps. .github/workflows/ci.yml adds cut-release-reproducible: cuts the same commit twice with --no-cache, diffs all four artifacts + SHA256SUMS byte-for-byte, recomputes checksums against the emitted manifest, and reuses tests/qemu/test_distrib_boot.sh (unmodified) to boot the freshly-cut bundle to a real SYSTEM login. Gated behind a new `release` path filter. CMakeLists.txt adds an optional `make release` convenience target wrapping the script. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
CI's cut-release-reproducible job caught a real byte diff in initramfs-ovmx-slim.cpio.gz between two independent --no-cache cuts of the same commit (vmlinuz, ovmx-distrib.img, ovmx-os.kit were all already byte-identical). Root-caused by direct measurement, not guessing: isolated reproducers for both the kernel modules (vms.ko/vmsfs.ko via kbuild) and the static musl binaries (STARTUP.EXE/INITIALIZE.EXE/vms_mount_helper) proved BYTE-IDENTICAL across two independent --no-cache container builds -- ruling out the "kernel modules embed build metadata" hypothesis. The actual cause: GNU cpio's "newc" format embeds the REAL FILESYSTEM INODE NUMBER of every entry, which is not deterministic across independent container builds even when every file's content and mtime are identical (verified directly with two byte-identical directory trees built independently on the same host). Fix: add --reproducible to every `cpio -o -H newc` invocation in distro/Dockerfile.bootable (fat/slim/noexec/nodev initramfs packing) -- GNU cpio's own name for --ignore-devno --ignore-dirnlink --renumber-inodes. Verified locally: two independently-created, byte-identical directory trees now produce byte-identical cpio archives with this flag; without it they differ at the same header offset (the inode field) the CI failure pointed to. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
baron-3dl
force-pushed
the
worktree-agent-a30e7760796101156
branch
from
August 10, 2026 14:53
3a30d51 to
677df2a
Compare
This was referenced Aug 10, 2026
Merged
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Foundation of the Release Engineering pillar (epic
vms-a84). Implementsvms-d73.tools/cut-release.sh: git-archives the requested commit to a clean/tmptree (never builds into the repo, per the standing containerized-build rule), drives the existingdistro/Dockerfile.bootablebuild viadocker buildx build --output=local, and writesdist/release-<version>/containingvmlinuz,initramfs-ovmx-slim.cpio.gz,ovmx-distrib.img,ovmx-os.kit,SHA256SUMS, and an OVMX-defined (Rule 8, explicitly labeled)release-manifest.jsonmapping component → version → sha256, including the OS kit's own internal file listing (assertsDCL.EXE/LOGINOUT.EXE/STARTUP.COMpresent, from the shipped kit itself).src/libvms/include/ovmx_identity.h(OVMX_PRODUCT_NAME/OVMX_PRODUCT_VERSION) — no version literal in the script.CMakeLists.txt: optionalmake releaseconvenience target wrapping the script.Reproducibility required normalizing every wall-clock timestamp the build stamps into shipped bytes:
distro/Dockerfile.bootablegains aSOURCE_DATE_EPOCHbuild-arg (default0), threaded into every initramfs pack step (file mtimes normalized, cpio member order sorted,gzip -ninstead ofgzip).tools/ovmx_kit_pack.c(kh_build_time) andtools/vmsfs_master.c(fh_created/fh_modified/fh_accessed) now readSOURCE_DATE_EPOCHinstead oftime(NULL)when set.cut-release.shdefaultsSOURCE_DATE_EPOCHto the cut commit's own timestamp, so two independent cuts of the same commit are deterministic automatically.CI (
.github/workflows/ci.yml, newcut-release-reproduciblejob, gated behind a newreleasepath filter):--no-cache(no shared build cache between them — proves reproducibility, not cache reuse).SHA256SUMSbyte-for-byte between the two cuts.release-manifest.json(defense against a bug in the script's own checksum step).tests/qemu/test_distrib_boot.shunmodified — bind-mounts the freshly-cut bundle's ownvmlinuz/initramfs-ovmx-slim.cpio.gz/ovmx-distrib.imgat the paths it expects — to boot the actual cut bundle to a real SYSTEM login prompt, rather than reinventing the boot proof.Verification so far
ctest(dev build): 123/124 pass. The 1 failure,env_identity_census_negctl, is a pre-existing, already-tracked dev-host-load timeout (vms-3f9) unrelated to any file this PR touches (it source-scanssrc/for env-var census declarations) — reproduced the same timeout in isolation, confirming it's host contention, not a regression.shellcheck tools/cut-release.sh: clean.actionlint .github/workflows/ci.yml: no new findings (pre-existing warnings only, all outside the new job).link-nativestage locally; full Dockerfile parses and the touchedbuilder-stage blocks were reviewed line-by-line for correct&&/\chaining.SOURCE_DATE_EPOCHoverride verified directly againstovmx_kit_pack: two packs with a fixed epoch are byte-identical; a pack without the override differs, confirming the override actually takes effect.Not yet run: the actual containerized 2×-build-plus-boot proof — that only runs in CI (
cut-release-reproducible), which this PR triggers. Two full from-scratch builds (~25–30 min cold each) plus the boot-smoke test make it the heaviest job in the workflow; watching CI now.Test plan
ctestbaseline (pre-existing flake noted, not caused by this change)shellcheck/actionlintcleancut-release-reproduciblejob passes (byte-identical artifacts across two independent--no-cachecuts + boot-to-login proof) — watching this before merge🤖 Generated with Claude Code